from typing import Any
from fastapi import Header, HTTPException, status
from jose import jwt, JWTError
from datetime import datetime, timedelta, timezone

from api.login import GetUsername, GetUserinfo

SECRET_KEY = "zhujie"  # 密钥
ALGORITHM = "HS256"  # 加密算法RS256
access_token_expires = timedelta(seconds=20)  # 过期时间, seconde:单位秒
refresh_token_expires = timedelta(seconds=30)


# 状态码字典
STATUS_CODES = {
    "OK": 200,
    "CREATED": 201,
    "ACCEPTED": 202,
    "NO_CONTENT": 204,
    "MOVED_PERMANENTLY": 301,
    "FOUND": 302,
    "NOT_MODIFIED": 304,
    "BAD_REQUEST": 400,
    "UNAUTHORIZED": 401,
    "FORBIDDEN": 403,
    "NOT_FOUND": 404,
    "METHOD_NOT_ALLOWED": 405,
    "REQUEST_TIMEOUT": 408,
    "INTERNAL_SERVER_ERROR": 500,
    "NOT_IMPLEMENTED": 501,
    "BAD_GATEWAY": 502,
    "SERVICE_UNAVAILABLE": 503,
    "GATEWAY_TIMEOUT": 504,
}

# 异常
class CustomHTTPException(HTTPException):
    def __init__(self, status_code: str, detail: Any = None, headers=None):
        status_code = STATUS_CODES.get(status_code, 500)  # Use 500 as default status code
        detail = detail or {"code": status_code}
        if isinstance(detail, dict):
            detail["code"] = status_code
        super().__init__(status_code=status_code, detail=detail, headers=headers)

def credentials_exception(err:str):
    return CustomHTTPException(
        status_code=err,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )


#  生成token方法
def create_access_token(*, data: dict, expires_delta: timedelta = timedelta(minutes=15)):
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + expires_delta
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


# 登录验证，登录成功返回token
def login_token(username: str, password: str):
    id = GetUserinfo(username, password)
    if id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    id = str(id)
    access_token = create_access_token(
        data={"sub": id}, expires_delta=access_token_expires
    )
    refresh_token = create_access_token(
        data={"sub": id}, expires_delta=refresh_token_expires
    )
    return {"code": STATUS_CODES["OK"], "msg": "success", "status": "ok",
            "data": {"access_token": access_token, "token_type": "bearer", "refresh_token": refresh_token}}



# 解码令牌并获取用户
def decode_token_and_get_user(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        id: str = payload.get("sub")
        if id is None:
            raise credentials_exception('UNAUTHORIZED') # 401
    except JWTError:
        raise credentials_exception('UNAUTHORIZED') # 401
    try:
        user = GetUsername(id)
        if user is None:
            raise credentials_exception('UNAUTHORIZED') # 401
    except Exception:
        raise credentials_exception('NOT_IMPLEMENTED') # 501
    return {"user":user,"id":id}



#  验证刷新token，通过刷新token获取新的token
def refresh_token_route(refresh_token: str):
    id = decode_token_and_get_user(refresh_token)["id"]
    return {"code": STATUS_CODES["OK"], "msg": "success", "status": "ok",
            "data": {"access_token": create_access_token(
                data={"sub": id}, expires_delta=access_token_expires
            ), "token_type": "bearer", "refresh_token": refresh_token}}


# 用户登录成功后，后面每次请求携带令牌验证方法，验证通过后才有权限获得数据
def get_current_user(authorization: str = Header(...)):
    token = authorization.split()[1]
    user = decode_token_and_get_user(token)['user']
    return user
